package net.liteheaven.xblib.common.java;

import android.text.TextUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 反射调用工具类
 */
public class ReflectUtil {

    /**
     * 调用方法
     * @param caller
     * @param function
     * @param args
     * @return
     */
    public static Object invokeMethod(Object caller, String function, Class<?> [] argsClass, Object [] args){

        if (caller == null){
            return null;
        }
        if (TextUtils.isEmpty(function)){
            return null;
        }
        int argsCount = 0;
        if (args != null){
            argsCount = args.length;
        }
        int argsClassCount = 0;
        if (argsClass != null){
            argsClassCount = argsClass.length;
        }
        if (argsClassCount != argsCount){
            throw new IllegalArgumentException("args error!");
        }

        Object ret = null;
        try {
            Method m;
            if (argsCount == 0){
                m = caller.getClass().getDeclaredMethod(function);
            }else{
                m = caller.getClass().getDeclaredMethod(function, argsClass);
            }
            m.setAccessible(true);
            ret = m.invoke(caller, args);
            m.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
            Throwable cause = e.getCause();
        }
        return ret;
    }

    /**
     * 调用构造器
     * @param callerCls
     * @param args
     * @return
     */
    public static Object invokeConstructor(Class<?> callerCls, Class<?> [] argsClass, Object [] args){
        if (callerCls == null){
            return null;
        }
        int argsCount = 0;
        if (args != null){
            argsCount = args.length;
        }
        int argsClassCount = 0;
        if (argsClass != null){
            argsClassCount = argsClass.length;
        }
        if (argsClassCount != argsCount){
            throw new IllegalArgumentException("args error!");
        }

        Object ret = null;
        try {
            Constructor c;
            if (argsCount == 0){
                c = callerCls.getDeclaredConstructor();
            }else{
                c = callerCls.getDeclaredConstructor(argsClass);
            }
            c.setAccessible(true);
            ret = c.newInstance(args);
            c.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }

    public static Object getFieldValue(Object obj, String fieldName) {
        if (obj == null || TextUtils.isEmpty(fieldName)) {
            return null;
        }

        Class<?> clazz = obj.getClass();
        while (clazz != Object.class) {
            try {
                Field field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field.get(obj);
            } catch (Exception e) {
            }
            clazz = clazz.getSuperclass();
        }
        return null;
    }

    public static void setFieldValue(Object obj, String fieldName, Object value) {
        if (obj == null || TextUtils.isEmpty(fieldName)) {
            return;
        }

        Class<?> clazz = obj.getClass();
        while (clazz != Object.class) {
            try {
                Field field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                field.set(obj, value);
                return;
            } catch (Exception e) {
            }
            clazz = clazz.getSuperclass();
        }
    }
}
